summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Luka Šijanec <anton@sijanec.eu>2021-09-25 18:29:34 +0200
committerAnton Luka Šijanec <anton@sijanec.eu>2021-09-25 18:29:34 +0200
commit7877e512c2f228e0e98340d30cfee44e14c29cd6 (patch)
treeb8d47722a7102c1a504f2aae827a271b23d9a1f2
parenti hope it's fixed now (magic?), though there's still a memory leak (diff)
downloaddiscord.c-7877e512c2f228e0e98340d30cfee44e14c29cd6.tar
discord.c-7877e512c2f228e0e98340d30cfee44e14c29cd6.tar.gz
discord.c-7877e512c2f228e0e98340d30cfee44e14c29cd6.tar.bz2
discord.c-7877e512c2f228e0e98340d30cfee44e14c29cd6.tar.lz
discord.c-7877e512c2f228e0e98340d30cfee44e14c29cd6.tar.xz
discord.c-7877e512c2f228e0e98340d30cfee44e14c29cd6.tar.zst
discord.c-7877e512c2f228e0e98340d30cfee44e14c29cd6.zip
-rw-r--r--Makefile3
-rw-r--r--README.md34
-rw-r--r--src/api.c11
-rw-r--r--src/h.c28
4 files changed, 35 insertions, 41 deletions
diff --git a/Makefile b/Makefile
index 8bc8aa4..8f2b580 100644
--- a/Makefile
+++ b/Makefile
@@ -52,6 +52,3 @@ gensupp:
cc misc/valgrind-supp-extractor.c -otmp/vse
G_SLICE=always-malloc G_DEBUG=gc-friendly valgrind $(VGARGS) --gen-suppressions=all ./discord.c
tmp/vse < valgrind-out.txt > tmp/gend.supp
-
-echo:
- echo $$DC_E
diff --git a/README.md b/README.md
index 8721154..5ea70a4 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ sudo apt install discord.c
you need to add [my apt repository](https://prog.sijanec.eu/).
-built packages only exist for `amd64`, `arm64` and `i386`. for other architectures grab the source package:
+built packages only exist for `amd64`, `arm64` and `i386` (`i686`). for other architectures grab the source package:
```
apt-get --install build discord.c
@@ -79,28 +79,12 @@ completing this task would make `discord.c` the first and the only alternative c
it would be useful to have an android port, and luckily this is possible with little effort due to the GTK broadway backend that interfaces with a HTML renderer, WebView for example.
-<!--
+## developer notes
-## working features
-
-* listing guilds and their channels, including private message channels
-* joining and listing past messages from those existing channels
-* sending messages into channels, ability to be joined into multiple channels at once
-* viewing attachments as links
-* joining voice channels, talking
-
-## missing features
-
-* check for permissions before join (needs roles parsing)
-* tagging people, parsing tags of people/channels/emotes
-* ability to join video calls and stream video
-* altering profile
-* parsing per-channel nicks
-* creating channels and creating PMs
-* invites
-* refreshing channel and guild lists whilst begin turned on
-* responding to SIGWINCH and reloading ncurses windows whenever terminal window is resized
-* refreshing sound devices whilst being turned on
-* checking for rare system failures (for example [a malloc/realloc that fails and returns NULL will probably lead to corruption and SIGSEGV](http://etalabs.net/overcommit.html))
-
--->
+* use an `i386` compatible machine with `debian` `bullseye` (I use a Dell Latitude D620)
+* debugging with valgrind: `make valgrind-prepare` once and `make valgrind` for profiling `./discord.c`
+* generating valgrind suppressions: `make gensupp`, running `make valgrind` afterwards will ignore all
+* `make cc` to compile code under `gcc`, `tcc` and `clang`
+* optimization is always 0, binaries always have debug symbols
+* `make -e CC=gcc` to choose a compiler instead of `cc`.
+* `make -e CC="clang -fsanitize=address" && ASAN_OPTIONS=detect_leaks=1` to use `clang` leak checker
diff --git a/src/api.c b/src/api.c
index c405cff..7171e3a 100644
--- a/src/api.c
+++ b/src/api.c
@@ -238,7 +238,11 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
role = &pass->api_io.guild->role;
while (*role)
role = &(*role)->next;
- *role = pass->api_io.guild->role;
+ if (!dc_find_ll_role(pass->api_io.guild->role, pass->api_io.role->id)) {
+ fprintf(stderr, "new role id=%lld (:\n", pass->api_io.role->id);
+ pass->api_io.role->next = NULL;
+ *role = pass->api_io.role;
+ }
pass->api_io.role->guild = pass->api_io.guild;
if (pass->api_io.role->name && !strncmp(pass->api_io.role->name, "@everyone", strlen(pass->api_io.role->name)))
pass->api_io.role->status |= DC_EVERYONE;
@@ -681,6 +685,11 @@ void dc_api_i (struct dc_api_io i) { /* this function does not call attached fun
}
}
struct dc_api_io dc_api_o (struct dc_api_io i /* for ->program */) {
+ if (!i.program) {
+ i.type = DC_API_STATUS;
+ i.status = DC_USER_ERROR;
+ return i;
+ }
if (i.program->lws_context)
lws_service(i.program->lws_context, 0);
for (size_t x = 0; x < i.program->clients_length; x++) {
diff --git a/src/h.c b/src/h.c
index bd20bf8..df7907f 100644
--- a/src/h.c
+++ b/src/h.c
@@ -51,6 +51,7 @@ enum dc_status { /* theese are flags and should be and-checked */
DC_REPLACE = 1 << 23, /* dc_add_x replace old with new on found, _free: only free members */
DC_EXPLICIT_NULL = 1 << 24, /* MEMB_GC will NULL this member (PROGRES?aftr free) (& clear bit) */
DC_EVERYONE = 1 << 25, /* role applies to all guild users */
+ DC_USER_ERROR = 1 << 26, /* lib user made an error, passed NULL pointer to _o for example */
DC_INTERNAL = DC_FROM_LWS | DC_FROM_API, /* call originates from an internal function */
}; /* note: when checking status, first check for DC_OK, if it's set then disregard errors! */
#define DC_ADMIN (1 << 3) /* not all enum fields are implemented/understood */
@@ -108,7 +109,7 @@ enum dc_api_io_type {
DC_API_REGISTER,/* i: pass a dc_client, to relogin FIX pr rt cl&cl->user not creat new */
/* o: the previously passed dc_client with set status */
DC_API_STATUS, /* i: N/A */
- /* o: new status message, pointer to internal string - tr0 */
+ /* o: check ->status */
DC_API_USER, /* i: query for user by id, pass dc_user-tr1 */
/* o: prev passed dc_user but filled (or not: ->status may indicate error) */
DC_API_ROLE, /* i: query for role by id, pass dc_role-tr1 */
@@ -665,6 +666,18 @@ enum dc_status dc_handle_ping (struct dc_api_io io, void * userdata) { /* tries
}
struct dc_program * dc_program_init () {
struct dc_program * s = calloc(1, sizeof(struct dc_program));
+ /* lws init, it may fail so we first do this to return NULL without memleak (thanks, clang) */
+ struct lws_context_creation_info info;
+ memset(&info, 0, sizeof(info));
+ info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+ info.port = CONTEXT_PORT_NO_LISTEN; /* we are not listening - we are a client */
+ info.protocols = dc_lws_protocols;
+ info.fd_limit_per_thread = DC_LWS_MAX_FD;
+ if (!(s->lws_context = lws_create_context(&info))) {
+ lwsl_err("lws init failed\n");
+ free(s);
+ return NULL; /* of course our UI does not check for failure of init function, so the */
+ } /* program will just crash, but I assume lws init will never fail (correct me if I'm wrong) */
DC_ISASIQ(client);
DC_ISASIQ(guild);
DC_ISASIQ(channel);
@@ -674,17 +687,6 @@ struct dc_program * dc_program_init () {
DC_ISASIQ(permission);
DC_ISASIQ(attached_function);
DC_ISASIQ(api_io);
- /* lws init */
- struct lws_context_creation_info info;
- memset(&info, 0, sizeof(info));
- info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
- info.port = CONTEXT_PORT_NO_LISTEN; /* we are not listening - we are a client */
- info.protocols = dc_lws_protocols;
- info.fd_limit_per_thread = DC_LWS_MAX_FD;
- if (!(s->lws_context = lws_create_context(&info))) {
- lwsl_err("lws init failed\n");
- return NULL;
- }
struct dc_api_io io; /* attach a function for pinging wss of every client */
memset(&io, 0, sizeof(io));
io.type = DC_API_ATTACH;
@@ -780,6 +782,7 @@ DC_GEN_X(channel, CHANNEL)
DC_FIND_LL_X(channel)
DC_GEN_X(guild, GUILD)
DC_GEN_X(role, ROLE)
+DC_FIND_LL_X(role)
#define DC_ISAE(a) &(a), &(a##_sizeof), &(a##_length) /* ISA Expand */
#define DC_ISAN NULL, NULL, NULL /* ISA NULL */
#define DC_TRANSFER_CHANNEL(n, o) do { /* n is going to DC_REPLACE o, transfer important data */ \
@@ -799,6 +802,7 @@ DC_GEN_X(role, ROLE)
void dc_transfer_role (struct dc_role * n, struct dc_role * o) {
n->next = o->next;
if (!n->users_length) { /* if we didn't update users array in the new role object */
+ free(n->users); /* thanks, clang, we have to free pointer array before overwriting it! */
n->users = o->users;
n->users_sizeof = o->users_sizeof;
n->users_length = o->users_sizeof;